package com.jfeinstein.jazzyviewpager;

import ohos.agp.animation.Animator;
import ohos.agp.components.AttrHelper;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.StackLayout;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.agp.utils.Rect;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;

/**
 * OutlineContainer
 */
public class OutlineContainer extends StackLayout implements Component.DrawTask {
    private static final long ANIMATION_DURATION = 500;
    private static final long FRAME_DURATION = 1000 / 60;

    private Paint mOutlinePaint;
    private boolean mIsRunning = false;
    private long mStartTime;
    private float mAlpha = 1.0f;

    private Animatable mAnimatable = new Animatable();
    private EventHandler mEventHandler = new EventHandler(EventRunner.getMainEventRunner());

    public OutlineContainer(Context context) {
        super(context);
        init();
    }

    public OutlineContainer(Context context, AttrSet attrs) {
        super(context, attrs);
        init();
    }

    public OutlineContainer(Context context, AttrSet attrs, String defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        mOutlinePaint = new Paint();
        mOutlinePaint.setAntiAlias(true);
        mOutlinePaint.setStrokeWidth(AttrHelper.vp2px(2, getContext()));
        mOutlinePaint.setColor(Color.CYAN);
        mOutlinePaint.setStyle(Paint.Style.STROKE_STYLE);

        int padding = AttrHelper.vp2px(10, getContext());
        setPadding(padding, padding, padding, padding);
        addDrawTask(this);
    }

    /**
     * dispatchDraw
     * @param canvas canvas
     */
    protected void dispatchDraw(Canvas canvas) {
        int offset = AttrHelper.vp2px(5, getContext());
        if (mOutlinePaint.getColor() != JazzyViewPager.sOutlineColor) {
            mOutlinePaint.setColor(JazzyViewPager.sOutlineColor);
        }
        mOutlinePaint.setAlpha((int)(mAlpha * 255));
        Rect rect = new Rect(offset, offset, getEstimatedWidth() - offset, getEstimatedHeight() - offset);
        canvas.drawRect(rect, mOutlinePaint);
    }

    /**
     * setOutlineAlpha
     * @param alpha alpha
     */
    public void setOutlineAlpha(float alpha) {
        mAlpha = alpha;
    }

    class Animatable extends Animator {
        @Override
        public boolean isRunning() {
            return mIsRunning;
        }

        @Override
        public void start() {
            if (mIsRunning) {
                return;
            }
            mIsRunning = true;
            mStartTime = getDuration();
            mEventHandler.postTask(mUpdater);
        }

        @Override
        public void stop() {
            if (!mIsRunning) {
                return;
            }
            mIsRunning = false;
        }
    }

    /**
     * isRunning
     * @return ture/false
     */
    public boolean isRunning() {
        return mAnimatable.isRunning();
    }

    /**
     * start
     */
    public void start() {
        mAnimatable.start();
    }

    /**
     * stop
     */
    public void stop() {
        mAnimatable.stop();
    }

    private final Runnable mUpdater = new Runnable() {
        @Override
        public void run() {
            long now = mAnimatable.getDuration();
            long duration = now - mStartTime;
            if (duration >= ANIMATION_DURATION) {
                mAlpha = 0.0f;
                invalidate();
                stop();
                return;
            } else {
                mAlpha = getInterpolation(1 - duration / (float) ANIMATION_DURATION);
                invalidate();
            }
            mEventHandler.postTask(mUpdater, FRAME_DURATION);
        }
    };

    /**
     * getInterpolation
     * @param t1 interval
     * @return interval
     */
    public float getInterpolation(float t1) {
        t1 -= 1.0f;
        return t1 * t1 * t1 + 1.0f;
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        dispatchDraw(canvas);
    }
}
